package com.pivotal.cloud.crypto.encrypt;

import com.pivotal.cloud.crypto.keygen.BytesKeyGenerator;
import com.pivotal.cloud.crypto.utils.EncodingUtil;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.ParametersWithIV;

/**
 * @className: com.pivotal.cloud.security.crypto.encrypt.BouncyCastleAesCbcBytesEncryptor
 * @projectName: PivotalCloud项目
 * @module: PivotalCloud项目-BouncyCastleAesCbcBytesEncryptor类，主要位于Security安全模块-Aes加密模块
 * @content: BouncyCastleAesCbcBytesEncryptor-Aes加密
 * @author: Powered by Marklin
 * @datetime: 2025-06-25 23:00
 * @version: 1.0.0
 * @copyright: Copyright © 2018-2025 PivotalCloud Systems Incorporated. All rights
 * reserved.
 */
public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryptor {

	public BouncyCastleAesCbcBytesEncryptor(String password, CharSequence salt) {
		super(password, salt);
	}

	public BouncyCastleAesCbcBytesEncryptor(String password, CharSequence salt, BytesKeyGenerator ivGenerator) {
		super(password, salt, ivGenerator);
	}

	@Override
	@SuppressWarnings("deprecation")
	public byte[] encrypt(byte[] bytes) {
		byte[] iv = this.ivGenerator.generateKey();
		PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(
				new CBCBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()), new PKCS7Padding());
		blockCipher.init(true, new ParametersWithIV(this.secretKey, iv));
		byte[] encrypted = process(blockCipher, bytes);
		return EncodingUtil.concatenate(iv, encrypted);
	}

	@Override
	@SuppressWarnings("deprecation")
	public byte[] decrypt(byte[] encryptedBytes) {
		byte[] iv = EncodingUtil.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength());
		encryptedBytes = EncodingUtil.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length);
		PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(
				new CBCBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()), new PKCS7Padding());
		blockCipher.init(false, new ParametersWithIV(this.secretKey, iv));
		return process(blockCipher, encryptedBytes);
	}

	private byte[] process(BufferedBlockCipher blockCipher, byte[] in) {
		byte[] buf = new byte[blockCipher.getOutputSize(in.length)];
		int bytesWritten = blockCipher.processBytes(in, 0, in.length, buf, 0);
		try {
			bytesWritten += blockCipher.doFinal(buf, bytesWritten);
		}
		catch (InvalidCipherTextException ex) {
			throw new IllegalStateException("unable to encrypt/decrypt", ex);
		}
		if (bytesWritten == buf.length) {
			return buf;
		}
		byte[] out = new byte[bytesWritten];
		System.arraycopy(buf, 0, out, 0, bytesWritten);
		return out;
	}

}
